package cn.bugstack.springframework.beans.factory.support;

import cn.bugstack.springframework.beans.BeansException;
import cn.bugstack.springframework.beans.factory.BeanFactory;
import cn.bugstack.springframework.beans.factory.FactoryBean;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;
import cn.bugstack.springframework.beans.factory.config.BeanPostProcessor;
import cn.bugstack.springframework.beans.factory.config.ConfigurableBeanFactory;
import cn.bugstack.springframework.util.ClassUtils;
import cn.bugstack.springframework.util.StringValueResolver;

import java.util.ArrayList;
import java.util.List;

/**
 * 抽象类 AbstractBeanFactory 是一个bean工厂，负责管理bean的创建和检索。它继承自 DefaultSingletonBeanRegistry，
 * 并实现了 BeanFactory 接口。
 *
 * 这里将AbstractBeanFactory之前继承的DefaultSingletonBeanRegistry修改为FactoryBeanRegistrySupport为了
 * 扩展出创建FactoryBean的功能，需要在链路服务上截出一段来处理额外的服务，再将链条连接上。
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    /** ClassLoader to resolve bean class names with, if necessary */
    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

    /** BeanPostProcessors to apply in createBean */
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
    /**
     * 用于存储字符串解析器的列表，这些解析器可用于解析注解属性值等。
     */
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();

    /**
     * 向解析器列表中添加一个字符串值解析器。
     *
     * @param valueResolver 要添加的字符串值解析器，它是一个接口，用于解析字符串值。
     */
    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    /**
     * 解析给定值中的嵌入值。它会遍历所有已添加的解析器，使用它们来解析值，直到得到最终结果。
     *
     * @param value 需要解析的字符串值。
     * @return 解析后的字符串值。如果没有任何解析器修改该值，则返回原始值。
     */
    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value; // 初始化结果为传入的值
        // 遍历所有解析器，依次解析传入的值
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result; // 返回最终解析后的值
    }


    /**
     * 通过bean的名称获取bean实例。如果bean实例不存在，则会尝试创建一个新的实例。
     *
     * @param name 待获取的bean的名称。
     * @return 返回bean的实例。
     * @throws BeansException 如果获取bean时发生错误。
     */
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null);
    }


    /**
     * 通过bean的名称获取bean实例，允许提供额外的参数来影响bean的创建过程。
     *
     * @param name 待获取的bean的名称。
     * @param args 传递给bean构造函数的参数。
     * @return 返回bean的实例。
     * @throws BeansException 如果获取bean时发生错误。
     */
    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, args);
    }

    /**
     * 根据给定的名称和类型获取bean实例。此方法为泛型方法，通过传入的名称和类型参数，返回一个匹配的bean实例。
     *
     * @param name 要获取的bean的名称。
     * @param requiredType 需要的bean的类型。
     * @return 返回一个与给定名称和类型匹配的bean实例。如果找不到匹配的bean，将抛出BeansException。
     * @throws BeansException 如果无法获取bean实例。
     * @see BeanFactory#getBean(Class)
     */
    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name); // 通过bean的名称获取bean实例，并将其强制转换为泛型T类型。
    }


    /**
     * 内部方法，用于实际获取bean的实例。首先尝试从单例缓存中获取bean，如果不存在，则根据bean名称和定义创建新的bean实例。
     * 在这段代码中，<T> 表示该方法可以返回任意类型的对象，并且在编译时由调用者指定具体的返回类型。
     * 在方法的返回语句 (T) bean 和 (T) createBean(...) 中，将 bean 强制转换为类型 T，这是类型擦除后的操作，编译器会根据调用时的上下文来确定 T 的具体类型。
     * 调用方法时指定返回类型为 String
     * String bean = doGetBean("beanName", args);
     * 调用方法时指定返回类型为 Integer
     * Integer bean = doGetBean("beanName", args);
     * @param name 待获取bean的名称。
     * @param args 传递给bean构造函数的参数数组。
     * @return 返回bean的实例。
     */
    protected <T> T doGetBean(final String name, final Object[] args) {
        // <property name="userDao" ref="proxyUserDao"/>
        // <bean id="proxyUserDao" class="cn.bugstack.springframework.test.bean.ProxyBeanFactory"/>
        Object sharedInstance = getSingleton(name);

        if (null != sharedInstance) {
            // 如果是 FactoryBean，则需要调用 FactoryBean#getObject
            // 通过FactoryBean的getObject方法实现二次获取所需对象的动态代理对象的能力
            return (T) getObjectForBeanInstance(sharedInstance, name);
        }

        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition, args);
        return (T) getObjectForBeanInstance(bean, name);
    }

    /**
     * 根据bean实例获取相应的对象。
     * 如果bean实例不是FactoryBean类型，则直接返回该实例。
     * 如果是FactoryBean类型，则尝试从缓存中获取对象，若未缓存，则通过FactoryBean获取对象。
     *
     * @param beanInstance Bean实例
     * @param beanName Bean名称
     * @return 根据bean实例获取的对象。如果是FactoryBean类型，则返回FactoryBean创建的对象；否则，返回bean实例本身。
     */
    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {

        // 如果bean实例不是FactoryBean类型，则直接返回该实例
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }

        // 尝试从缓存中获取对象
        Object object = getCachedObjectForFactoryBean(beanName);

        // 如果对象未缓存，通过FactoryBean获取对象
        if (object == null) {
            FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factoryBean, beanName);
        }

        return object;
    }


    /**
     * 获取指定bean名称的bean定义。这是一个抽象方法，需要在具体实现中提供bean定义的获取逻辑。
     *
     * @param beanName 待获取bean定义的名称。
     * @return 返回bean的定义。
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName);

    /**
     * 根据bean名称、bean定义以及可能的构造函数参数创建bean实例。这是一个抽象方法，具体实现在创建bean实例时可能需要进行额外的逻辑处理。
     *
     * @param beanName 待创建bean的名称。
     * @param beanDefinition 描述bean的定义。
     * @param args 传递给bean构造函数的参数数组。
     * @return 返回创建的bean实例。
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args);


    /**
     * 添加一个BeanPostProcessor后置处理器到列表中。
     * 如果该处理器已经存在于列表中，则会先移除它，然后再重新添加，确保其位置可能发生变化。
     *
     * @param beanPostProcessor 要添加的BeanPostProcessor实例
     */
    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
        // 先尝试移除，确保即使已存在也能重新添加
        this.beanPostProcessors.remove(beanPostProcessor);
        // 重新添加到列表中
        this.beanPostProcessors.add(beanPostProcessor);
    }


    /**
     * 获取将应用于由该工厂创建的bean的BeanPostProcessor列表。
     *
     * @return List<BeanPostProcessor> 包含所有将被应用的BeanPostProcessor的列表。
     */
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;     // 返回存储的BeanPostProcessor列表
    }

    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }
}

